package net.alche.sdd.fatis.macro;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.alche.fa.core.model.Logic;
import net.alche.fa.core.parse.FaKeyWord;
import net.alche.sdd.fatis.SddFatisMacro;

public class SddFatisMacroIf {
  public static final Logger logger = LoggerFactory.getLogger(SddFatisMacroIf.class);
  int continuLv = -1; // 跳过的行
  int continuLv2 = -1;
  int continuLv3 = -1;
  SddFatisMacro macroPar;
  public SddFatisMacroIf(SddFatisMacro macro) {
    this.macroPar = macro;
  }

  public void setContinue(int lv) {
    if (lv == -1) {
      continuLv = continuLv2;
      continuLv2 = continuLv3;
      continuLv3 = -1;
    } else {
      continuLv3 = continuLv2;
      continuLv2 = continuLv;
      continuLv = lv;
    }
  }

  public int getContinueLv() {
    return continuLv;
  }

  public boolean needContinue(int lv) {
    if (continuLv == -1) {
      return false;
    }
    if (getContinueLv() < lv)
      return true;
    setContinue(-1);
    return false;
  }

  public boolean getBoolVal(Logic g) {
    String what = g.getWhat();
    Logic compareLogic = g;
    if (g.getLogicData() != null && "(".equals(g.getLogicData().getWhat()) && "if".equals(g.getWhat())) {
      compareLogic = g.getLogicObj();
    } else if ("if".equals(g.getWhat()) && g.getLogicObj() != null) {
      compareLogic = g.getLogicObj();
    }
    if ("&&".equals(compareLogic.getWhat()) || "||".equals(compareLogic.getWhat())) {
      what = compareLogic.getWhat();
    }
    Object varData = null;
    if (".".equals(compareLogic.getWhat()) || !what.equals("!") && "!".equals(compareLogic.getWhat())) {
      varData = getLogicValue(compareLogic);
    } else {
      varData = getLogicObjVal(compareLogic);
    }
    if (what.equals("||")) {
      if ((boolean) varData) {
        return true;
      }
    } else if (what.equals("&&")) {
      if (!(boolean) varData) {
        return false;
      }
    }
    String eq = compareLogic.getWhat();
    boolean isOk = false;
    if (eq == null || ".".equals(eq)) {
      isOk = (boolean) varData;
    } else {
      Object data = getLogicDataVal(compareLogic);
      try {
        isOk = compare(varData, eq, data);
        // logger.info("run compare: {} {} {} = {}", varData, eq, data, isOk);
      } catch (Exception ex) {
        logger.error("compare: {} {} {}", varData, eq, varData);
        ex.printStackTrace();
      }
    }
    if (what.equals("!")) {
      isOk = !isOk;
    }
    return isOk;
  }

  public boolean compare(Object ov, String runType, Object value) {
    if (ov != null && value != null) {
      String v1 = getString(ov);
      String v2 = getString(value);
      // null
      if (runType.equals("&&")) {
        return v1.equals("true") && v2.equals("true");
      } else if (runType.equals("||")) {
        return v1.equals("true") || v2.equals("true");
      } else if (v1.equals("[^null^]") || v2.equals("[^null^]")) {
        if (runType.equals("!="))
          return ov != null && value != null;
        else
          return ov == null || value == null;
      } else if (runType.equals("==")) {
        return v1.equals(v2);
      } else if (runType.equals("!=")) {
        return !v1.equals(v2);
      } else {
        double d1 = Double.parseDouble(v1);
        double d2 = Double.parseDouble(v2);
        switch (runType) {
          case ">":
            return d1 > d2;
          case ">=":
            return d1 >= d2;
          case "<":
            return d1 < d2;
          case "<=":
            return d1 <= d2;
        }
      }
    }
    return false;
  }

  public Boolean getBool(Object obj) {
    if (obj instanceof Boolean) {
      return (Boolean) obj;
    }
    return Boolean.parseBoolean(obj.toString());
  }

  public String getString(Object obj) {
    return obj.toString();
  }

  public Object getLogicValue(Logic g) {
    Object v;
    if (g.getWhat() == null) {
      return this.getLogicObjVal(g);
    } else {
      v = getBoolVal(g);
    }
    return v;
  }

  public Object getLogicObjVal(Logic logic) {
    if (logic.getFaObjValue() != null) {
      return logic.getFaObjValue().getValue();
    }
    if (logic.getLogicObj() != null) {
      if (logic.getLogicObj().getWhat() == null && logic.getLogicObj().getFaObjValue() != null) {
        return logic.getLogicObj().getFaObjValue().getValue();
      } else if (logic.getLogicObj().getWhat() == null && logic.getLogicObj().getObj() != null) {
        return getParam(logic.getLogicObj().getObj());
      }
      return getBoolVal(logic.getLogicObj());
    }
    if (logic.getObj() != null) {
      return getParam(logic.getObj());
    }
    return null;
  }

  public Object getParam(String val) {
    if ("true".equals(val)) {
      return true;
    }
    if ("false".equals(val)) {
      return false;
    }
    if ("''".equals(val)) {
      return "";
    }
    if ("\"\"".equals(val)) {
      return "";
    }
    if ("null".equals(val)) {
      return "[^null^]";
    }
    if ("'null'".equals(val)) {
      return "null";
    }
    if (FaKeyWord.isNumber(val)) {
      return val;
    }
    return macroPar.getParam(val);
  }

  public Object getLogicDataVal(Logic logic) {
    if (logic.getFaDataValue() != null) {
      return logic.getFaDataValue().getValue();
    }
    if (logic.getLogicData() != null) {
      if (logic.getLogicData().getWhat() == null && logic.getLogicData().getFaObjValue() != null) {
        return logic.getLogicData().getFaObjValue().getValue();
      }
      return this.getBoolVal(logic.getLogicData());
    }
    if (logic.getData() != null) {
      return getParam(logic.getData());
    }
    return null;
  }
}
